﻿#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Script.Services;
using System.Web.Services;
using ProcolAI;

#endregion

namespace ProcolServices {
    /// <summary>
    /// Summary description for MatchingService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(false)]
    [ScriptService]
    public class MatchingService : WebService {
        private readonly ProcolDataContext db = new ProcolDataContext();

        [WebMethod]
        public SimilarityMatches.MatchEntry[] TestMatches() {
            var projects = GenerateTestDatabase();

            // Get similar projects
            return SimilarityMatches.GetMatches(projects, "Proyecto Uno", 5);
            //return SimilarityMatches.GetMatches(Transpose(projects), "comercio", 5);
            // Get similar tags
        }

        [WebMethod]
        public SimilarityMatches.MatchEntry[] GetSimilarProjects(int pid, int max) {
            var projects = GenerateProjectTagDatabase();
            var matches = SimilarityMatches.GetMatches(projects, pid.ToString(), max);


            foreach (var v in matches) {
                int id;
                SimilarityMatches.MatchEntry mE = v;

                v.Extra = (from p in db.Projects
                           where Int32.TryParse(mE.Id, out id) && p.ProjectId == id
                           select p.Name).First();
                v.Value *= 100;
                v.Value = (double)Decimal.Round((decimal)v.Value, 2);
            }

            var positive = from m in matches
                           where m.Value > 0
                           select m;

            return positive.ToArray();
        }

        [WebMethod]
        public SimilarityMatches.MatchEntry[] GetSimilarUsers(int uid, int max) {
            var users = GenerateUserInterestDatabase();
            var matches = SimilarityMatches.GetMatches(users, uid.ToString(), max);


            foreach (var v in matches) {
                int id;
                SimilarityMatches.MatchEntry mE = v;

                v.Extra = (from u in db.Users
                           where Int32.TryParse(mE.Id, out id) && u.UserId == id
                           select u.Username).First();
                v.Value *= 100;
                v.Value = (double)Decimal.Round((decimal)v.Value, 2);
                }

            var positive = from m in matches
                           where m.Value > 0
                           select m;

            return positive.ToArray();
        }

        private static Dictionary<string, Dictionary<string, double>> GenerateTestDatabase() {
            var dict = new Dictionary<string, Dictionary<string, double>>();
            var projects = new[] {
                    "Proyecto Uno:compu,meca,dise,ingind,valores,comercio",
                    "Proyecto Dos:compu,meca,dise,ingind,comercio,valores", "Proyecto Tres:compu,meca,ingind,comercio",
                    "Proyecto Cuatro:meca,dise,comercio,ingind,valores"
            };

            foreach (var p in projects) {
                var info = p.Split(':');
                var tags = info[1].Split(',');
                var orderedTags = from t in tags
                                  //                                  orderby t  // Uncomment if order matters
                                  select t.Trim();
                var project = info[0];
                var value = 0;
                var maxCount = orderedTags.Count();

                dict[project] = new Dictionary<string, double>();

                foreach (var tag in orderedTags)
                    dict[project][tag] = maxCount - value++;
            }

            return dict;
        }

        private Dictionary<string, Dictionary<string, double>> GenerateProjectTagDatabase() {
            var dict = new Dictionary<string, Dictionary<string, double>>();
            var projects = from p in db.Projects
                           select new { p.ProjectId, p.Tags };
            var tagList = (from t in String.Join("|", (from p in db.Projects
                                                       select String.Join("|", p.Tags.Split(','))).ToArray()).Split('|')
                           select t).Distinct();
            foreach (var p in projects) {
                var tags = p.Tags.Split(',');
                var orderedTags = from t in tags
                                  //                                  orderby t  // Uncomment if order matters
                                  select t.Trim();

                var value = 0;
                var maxCount = orderedTags.Count(); 
                
                dict[p.ProjectId.ToString()] = new Dictionary<string, double>();

                foreach (var tag in orderedTags)
                    dict[p.ProjectId.ToString()][tag] = maxCount - value++; //random.NextDouble() * lastValue;

                foreach (var tag in tagList)
                    if (!dict[p.ProjectId.ToString()].ContainsKey(tag))
                        dict[p.ProjectId.ToString()][tag] = 0;
            }

            return dict;
        }

        private Dictionary<string, Dictionary<string, double>> GenerateUserInterestDatabase() {
            var dict = new Dictionary<string, Dictionary<string, double>>();
            var users = from u in db.Users
                        let userInterests = (from i in db.UserInterests
                                             where i.UserId == u.UserId
                                             select i.InterestId)
                        let interestNames = (from n in db.InterestNames
                                             where userInterests.Contains(n.InterestId) && n.LanguageId == 1
                                             select n.Name.ToLower()).ToArray()
                        where userInterests.Count() > 0
                        select new { u.UserId, Interests = String.Join(",", interestNames) };

            var interestList = (from n in db.InterestNames
                                where n.LanguageId == 1
                                select n.Name.ToLower()).ToArray();

            foreach (var u in users) {
                var interests = u.Interests.Split(',');
                var orderedInterests = from t in interests
                                       //                                  orderby t  // Uncomment if order matters
                                       select t.Trim();

                var value = 0;
                var maxCount = orderedInterests.Count();

                dict[u.UserId.ToString()] = new Dictionary<string, double>();

                foreach (var interest in orderedInterests)
                    dict[u.UserId.ToString()][interest] = maxCount - value++; //random.NextDouble() * lastValue;

                foreach (var interest in interestList)
                    if (!dict[u.UserId.ToString()].ContainsKey(interest))
                        dict[u.UserId.ToString()][interest] = 0;
            }

            return dict;
        }

        private static Dictionary<string, Dictionary<string, double>> Transpose(
                Dictionary<string, Dictionary<string, double>> dict) {
            var newDict = new Dictionary<string, Dictionary<string, double>>();

            foreach (var key in dict.Keys) {
                foreach (var valueDict in dict[key]) {
                    if (!newDict.ContainsKey(valueDict.Key))
                        newDict[valueDict.Key] = new Dictionary<string, double>();

                    newDict[valueDict.Key][key] = dict[key][valueDict.Key];
                }
            }

            return newDict;
        }
    }
}